package com.mrx.commons.util;

import com.mrx.commons.util.asserts.Asserts;
import com.mrx.commons.util.function.XRunnable;
import com.mrx.commons.util.function.XSupplier;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author : 肖康宁
 * @since : 2022-12-08 15:07
 **/
public class LambdaUtil {

    private static final Logger logger = LoggerFactory.getLogger(LambdaUtil.class);

    /**
     * 使用 obj 作为参数给 consumer 消费, 最后返回 obj
     *
     * @param obj      要消费的对象
     * @param consumer 消费者函数, 可以在这里对 obj 做一些操作
     */
    public static <T> T with(T obj, Consumer<T> consumer) {
        consumer.accept(obj);
        return obj;
    }

    /**
     * 获取指定的 bean 的实例并将其用作 consumer 的参数, 返回 bean 对象
     *
     * @param bean     要获取的 bean 的 class
     * @param consumer 消费 bean 的函数, 可以在这里对 bean 做一些操作
     * @see #with(Object, Consumer)
     */
    @SneakyThrows
    public static <T> T withBean(Class<T> bean, Consumer<T> consumer) {
        return with(bean.getConstructor().newInstance(), consumer);
    }

    public static long runMeasure(Runnable r) {
        long start = System.currentTimeMillis();
        r.run();
        return System.currentTimeMillis() - start;
    }

    public static <T, R> R map(T obj, Function<T, R> mapper) {
        return mapper.apply(obj);
    }

    @SneakyThrows
    public static void withField(Field field, Object target, Consumer<Object> consumer) {
        field.setAccessible(true);
        consumer.accept(field.get(target));
    }

    @SneakyThrows
    public static void withMethod(Method method, Object target, Consumer<Object> consumer, Object... args) {
        if (!method.canAccess(target)) method.setAccessible(true);
        consumer.accept(method.invoke(target, args));
    }

    @SneakyThrows
    public static void withFiled(Object target, String filedName, Consumer<Object> consumer) {
        withField(target.getClass().getDeclaredField(filedName), target, consumer);
    }

    @SuppressWarnings("unchecked")
    public static <T> T runCaching(XSupplier<T> run, Supplier<Object> caching) {
        try {
            return run.get();
        } catch (Exception e) {
            logger.warn("出现异常:", e);
            Object o = caching.get();
            errorHandler(o);
            return (T) o;
        }
    }

    public static void runCaching(XRunnable runnable, Supplier<Object> supplier) {
        try {
            runnable.run();
        } catch (Exception e) {
            logger.warn("出现异常:", e);
            errorHandler(supplier.get());
        }
    }

    private static void errorHandler(Object o) {
        if (o instanceof RuntimeException) throw (RuntimeException) o;
        if (o instanceof Asserts) throw ((Asserts) o).getException();
    }

}
